package jmine.tec.web.wicket.component.command.button;

import java.io.Serializable;
import java.util.Set;

import jmine.tec.web.wicket.BeanReference;
import jmine.tec.web.wicket.spring.SpringBeanReference;
import bancosys.tec.persist.PersistenceController;
import bancosys.tec.persist.dao.BeanNotFoundException;

/**
 * Implementação base de botão que delega para suas implementações a execução das ações por entidade dentro de uma nova transação.
 * 
 * @author Rafael Volpato
 * @date Nov 24, 2011
 * @param <T> Tipo da entidade sobre qual a ação é executada.
 */
public abstract class SingleEntityExecutionButton<T> extends ExecutionButton {

    private final BeanReference<PersistenceController> persistenceControllerRef = SpringBeanReference.forName("persistenceController");

    /**
     * {@inheritDoc}
     */
    @Override
    protected final void executeSelected(Set<Serializable> selected) throws Exception {
        for (final Serializable entryId : selected) {
            try {

                this.persistenceControllerRef.get().executeTransacted(
                        new jmine.tec.utils.spring.SpringBeanReference.ThreadLocalCopyCallable() {
                            @Override
                            protected Void doCall() throws Exception {
                                T entity = SingleEntityExecutionButton.this.loadEntity(entryId);
                                SingleEntityExecutionButton.this.doExecute(entity);
                                return null;
                            }
                        });
                this.executionSucessfull();
            } catch (Exception e) {
                this.executionFailed(e);
            }
        }
    }

    /**
     * Executa a ação para a entidade.
     * 
     * @param entity entity
     */
    protected abstract void doExecute(T entity);

    /**
     * Carrega a entidade base para a execução a partir de seu id
     * 
     * @param entityId entity id
     * @return entidade associada ao id informado
     * @throws BeanNotFoundException se a entidade não existir mais na base de dados
     */
    protected abstract T loadEntity(Serializable entityId) throws BeanNotFoundException;
}
